﻿/**
* ...
* @author Andy Zupko
* @version 0.1
* @modifier Exey Panteleev
*/

package  {
	import flash.display.DisplayObject;
	import flash.display.Graphics;
	import flash.text.TextField;
	import org.papervision3d.events.InteractiveScene3DEvent;
	import org.papervision3d.materials.special.LineMaterial;
	import org.papervision3d.scenes.Scene3D;
	import org.papervision3d.cameras.Camera3D;
	import org.papervision3d.objects.DisplayObject3D;
	import org.papervision3d.core.geom.renderables.Vertex3D;
	import org.papervision3d.core.geom.Lines3D;
	import org.papervision3d.core.geom.renderables.Line3D;
	
	
	public class LSystem {

		public var angle:Number = Math.PI/2;
		public var rules:Array;
		public var iterations:Number = 3;
		public var startRule:String;
		public var lineCount:Number;
		public var cX:Number;
		public var cY:Number;
		public var cZ:Number;
		public var ratio:Number = 0.99;
		//public var cLine:Line3D;
		public var draw2D:Boolean;
		
		public var markerOld:DisplayObject3D = new DisplayObject3D();
		public var size:uint = 1;
		public var branchArray:Array = new Array();
		public var branchGroups:Array = new Array();
		public var branchGroupsCount:uint = 0;
		public var isBranchGroup:Boolean = false;
		//public var isNewBranchGroup:Boolean = false;
		public var bracketCounter:int = 0;
		
		public var trunk:Array = new Array();
		
		public var level:int = 0;
		public var oldLevel:int;
		public var oldLevel2:int;
		public var maxLevel:int;
		public var branchGrowingTime:Number = 0.01;
	
		public function LSystem(a:Number, it:Number = 3, sR:String = "F"){
			angle = a;
			iterations = it;
			rules = new Array();
			startRule = sR;
			lineCount = 0;
			cX = cY = cZ = 0;
		}
		

		//public function DrawSystem(system:String, scene:Scene3D, index:int, marker:DisplayObject3D, max:int, lines:Lines3D = null, graphics:Graphics = null, length:Number = 5){
		public function DrawSystem(system:String, index:int, marker:DisplayObject3D, max:int, length:Number = 50){
			var ix:Number, iy:Number, iz:Number, dx:Number, dy:Number, dz:Number, i:Number;
			//var l:Line3D;
			var l:Branch;
			//if(draw2D)
				//graphics.moveTo(marker.x, marker.y);
			
			max = Math.min(max, system.length);
			
			for(i=index;i<max;i++){
			
				markerOld.copyPosition(marker);

				switch(system.charAt(i)){
					
					case 'F': //Draw Forward
					case 'G':

						marker.moveForward(length);
						
						//if(draw2D)
							//graphics.lineTo(marker.x, marker.y);
						//else
							//l = new Line3D(lines, new LineMaterial(0x000000), size, new Vertex3D(markerOld.x, markerOld.y, markerOld.z), new Vertex3D(marker.x, marker.y, marker.z));
							//lines.addLine(l);
							l = new Branch(markerOld.x, markerOld.y, markerOld.z, marker.x, marker.y, marker.z);
							//l.growingTime = branchGrowingTime + randRange( branchGrowingTime/-2,  branchGrowingTime/2);
							l.growingTime = branchGrowingTime + (randRange( branchGrowingTime/-2,  branchGrowingTime/2)/10	);
							l.level = level;
							branchArray.push(l)
							level++;
							//trace("F ", branchGroupsCount, branchGroups.length)
							if (isBranchGroup)
								branchGroups[branchGroupsCount].push(l);
							else
								trunk.push(l)
							
						lineCount++;
						break;	
					
					case 'B': //Draw Backward
						
						marker.moveBackward(length);
						//if(draw2D)
							//graphics.lineTo(marker.x, marker.y);
						//else
							//l = new Line3D(lines, new LineMaterial(0x000000), size, new Vertex3D(markerOld.x, markerOld.y, markerOld.z), new Vertex3D(marker.x, marker.y, marker.z));
							//lines.addLine(l);
							l = new Branch(markerOld.x, markerOld.y, markerOld.z, marker.x, marker.y, marker.z);
							l.growingTime = branchGrowingTime + randRange( branchGrowingTime/-2, branchGrowingTime/2);
							l.level = level;
							branchArray.push(l)
							level++;
							//trace("B ", branchGroupsCount, branchGroups.length)
							if (isBranchGroup)
									branchGroups[branchGroupsCount].push(l);
							else
								trunk.push(l)
						lineCount++;
						break;
					
					case 'f': // move forward
						marker.moveForward(length);
						//if(draw2D)
							//graphics.moveTo(marker.x, marker.y);
						break;
						
					case 'b': //Draw Backward
						
						marker.moveBackward(length);
						
						//if(draw2D)
							//graphics.moveTo(marker.x, marker.y);

						break;
					
					case 'Y':
					case '+': // turn left
					
						marker.yaw(angle);
						break;
					case 'y':
					case '-': // turn right
						
						marker.yaw(-angle);
						break;
					case 'Z':
					case '>': // roll right
						
						marker.roll(angle);
						break;
					case 'z':
					case '<': // roll left
						
						marker.roll(-angle);
						break;
					case 'X':
					case '&': // pitch upwards
						
						marker.pitch(angle);
						break;
					case 'x':
					case '^': // pitch down
						
						marker.pitch(-angle);
						break;
						
					case '|':
						marker.pitch(180);
						break;
						
					case '!':
						//if(!draw2D)
							size *= ratio;
						length *= ratio;
						break;
						
					case '[': // push
					
					var bMark:DisplayObject3D = new DisplayObject3D();
					bMark.copyTransform(marker);
					
					//if(draw2D){
						//
						//i=DrawSystem(system, scene, i+1, bMark, max, null, graphics, length);
						//graphics.moveTo(marker.x, marker.y); // go back to where we were before the push
						//
					//}else{
						//l = new Line3D(lines, new LineMaterial(0x000000), size, new Vertex3D(markerOld.x, markerOld.y, markerOld.z), new Vertex3D(marker.x, marker.y, marker.z));
						//lines.addLine(l)
						//l = new Branch(markerOld.x, markerOld.y, markerOld.z, marker.x, marker.y, marker.z);
						//branchArray.push(l)
						
						//i=DrawSystem(system, scene, i+1, bMark, max, lines, graphics, length);
							
													
						
						if (bracketCounter <= 0) {
							branchGroups.push(new Array());
							isBranchGroup = true;
						}
						
						bracketCounter++;
						
						oldLevel = level;
						
						i=DrawSystem(system, i+1, bMark, max, length);
						
					
					//}
						i--; // for loop will increment again

						break;

					case ']':  // pop
					
						bracketCounter--;
						if (bracketCounter <= 0) {
							isBranchGroup = false;
							branchGroupsCount++;
						}
						
						
						level = oldLevel;
						return i+1;	   // +1 to skip the pop symbol
						// now, you might think you can get rid of the +1 here, and the -1 in the push, but you would be wrong
						break;	
						
					default:break;
				};//end switch
				
				
				
				
			}
		maxLevel = level;
		//trace("trunk ", trunk.length)
		//return;
		}
		
		public function GetCommand():String{
			
			var i:int, j:int, len:int, isRule:Boolean;
			var ret:String;
			var ts:String;
			var cRule:Rule;
			var cr:int = 0;
			
			ret = startRule;
			
			for(i=0;i<iterations;i++){
				ts = "";
				len = ret.length;
				for(j=0;j<len;j++){
					
					isRule = false;
					cr = 0;
					cRule = rules[cr];
					while(cRule && !isRule){
						
						if(ret.charAt(j) == cRule.axiom){
							
							ts+=cRule.rule;
							isRule = true;
							
						}
						cRule = rules[cr++];
					}
					if(!isRule){
						
						ts+=ret.charAt(j);
						
					}
					
				}
				ret = ts;
			}
			//trace("ret: ", ret);
			return ret;

		}
	
	private function randRange(min:Number, max:Number):Number {
		var randomNum:Number = (Math.random() * (max - min + 1)) + min;
		return randomNum;
	}//randRange without floor
	}
}

